/* do not edit automatically generated by mc from FIO.  */
/* FIO.mod provides a simple buffered file input/output library.

Copyright (C) 2001-2023 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */

#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#include <stddef.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#   include "GStorage.h"
#   include "Gmcrts.h"
#include <unistd.h>
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _FIO_H
#define _FIO_C

#   include "GSYSTEM.h"
#   include "GASCII.h"
#   include "GStrLib.h"
#   include "GStorage.h"
#   include "GNumberIO.h"
#   include "Glibc.h"
#   include "GIndexing.h"
#   include "GM2RTS.h"

typedef unsigned int FIO_File;

FIO_File FIO_StdErr;
FIO_File FIO_StdOut;
FIO_File FIO_StdIn;
#   define SEEK_SET 0
#   define SEEK_END 2
#   define UNIXREADONLY 0
#   define UNIXWRITEONLY 1
#   define CreatePermissions 0666
#   define MaxBufferLength (1024*16)
#   define MaxErrorString (1024*8)
typedef struct FIO_NameInfo_r FIO_NameInfo;

typedef struct FIO_buf_r FIO_buf;

typedef FIO_buf *FIO_Buffer;

typedef struct FIO_fds_r FIO_fds;

typedef FIO_fds *FIO_FileDescriptor;

typedef struct FIO__T7_a FIO__T7;

typedef char *FIO_PtrToChar;

typedef enum {FIO_successful, FIO_outofmemory, FIO_toomanyfilesopen, FIO_failed, FIO_connectionfailure, FIO_endofline, FIO_endoffile} FIO_FileStatus;

typedef enum {FIO_unused, FIO_openedforread, FIO_openedforwrite, FIO_openedforrandom} FIO_FileUsage;

struct FIO_NameInfo_r {
                        void *address;
                        unsigned int size;
                      };

struct FIO_buf_r {
                   unsigned int valid;
                   long int bufstart;
                   unsigned int position;
                   void *address;
                   unsigned int filled;
                   unsigned int size;
                   unsigned int left;
                   FIO__T7 *contents;
                 };

struct FIO__T7_a { char array[MaxBufferLength+1]; };
struct FIO_fds_r {
                   int unixfd;
                   FIO_NameInfo name;
                   FIO_FileStatus state;
                   FIO_FileUsage usage;
                   unsigned int output;
                   FIO_Buffer buffer;
                   long int abspos;
                 };

static Indexing_Index FileInfo;
static FIO_File Error;

/*
   IsNoError - returns a TRUE if no error has occured on file, f.
*/

extern "C" unsigned int FIO_IsNoError (FIO_File f);

/*
   IsActive - returns TRUE if the file, f, is still active.
*/

extern "C" unsigned int FIO_IsActive (FIO_File f);
extern "C" unsigned int FIO_Exists (const char *fname_, unsigned int _fname_high);
extern "C" FIO_File FIO_OpenToRead (const char *fname_, unsigned int _fname_high);
extern "C" FIO_File FIO_OpenToWrite (const char *fname_, unsigned int _fname_high);
extern "C" FIO_File FIO_OpenForRandom (const char *fname_, unsigned int _fname_high, unsigned int towrite, unsigned int newfile);

/*
   Close - close a file which has been previously opened using:
           OpenToRead, OpenToWrite, OpenForRandom.
           It is correct to close a file which has an error status.
*/

extern "C" void FIO_Close (FIO_File f);

/*
   exists - returns TRUE if a file named, fname exists for reading.
*/

extern "C" unsigned int FIO_exists (void * fname, unsigned int flength);

/*
   openToRead - attempts to open a file, fname, for reading and
                it returns this file.
                The success of this operation can be checked by
                calling IsNoError.
*/

extern "C" FIO_File FIO_openToRead (void * fname, unsigned int flength);

/*
   openToWrite - attempts to open a file, fname, for write and
                 it returns this file.
                 The success of this operation can be checked by
                 calling IsNoError.
*/

extern "C" FIO_File FIO_openToWrite (void * fname, unsigned int flength);

/*
   openForRandom - attempts to open a file, fname, for random access
                   read or write and it returns this file.
                   The success of this operation can be checked by
                   calling IsNoError.
                   towrite, determines whether the file should be
                   opened for writing or reading.
*/

extern "C" FIO_File FIO_openForRandom (void * fname, unsigned int flength, unsigned int towrite, unsigned int newfile);

/*
   FlushBuffer - flush contents of file, f.
*/

extern "C" void FIO_FlushBuffer (FIO_File f);

/*
   ReadNBytes - reads nBytes of a file into memory area, dest, returning
                the number of bytes actually read.
                This function will consume from the buffer and then
                perform direct libc reads. It is ideal for large reads.
*/

extern "C" unsigned int FIO_ReadNBytes (FIO_File f, unsigned int nBytes, void * dest);

/*
   ReadAny - reads HIGH(a) bytes into, a. All input
             is fully buffered, unlike ReadNBytes and thus is more
             suited to small reads.
*/

extern "C" void FIO_ReadAny (FIO_File f, unsigned char *a, unsigned int _a_high);

/*
   WriteNBytes - writes nBytes from memory area src to a file
                 returning the number of bytes actually written.
                 This function will flush the buffer and then
                 write the nBytes using a direct write from libc.
                 It is ideal for large writes.
*/

extern "C" unsigned int FIO_WriteNBytes (FIO_File f, unsigned int nBytes, void * src);

/*
   WriteAny - writes HIGH(a) bytes onto, file, f. All output
              is fully buffered, unlike WriteNBytes and thus is more
              suited to small writes.
*/

extern "C" void FIO_WriteAny (FIO_File f, unsigned char *a, unsigned int _a_high);

/*
   WriteChar - writes a single character to file, f.
*/

extern "C" void FIO_WriteChar (FIO_File f, char ch);

/*
   EOF - tests to see whether a file, f, has reached end of file.
*/

extern "C" unsigned int FIO_EOF (FIO_File f);

/*
   EOLN - tests to see whether a file, f, is upon a newline.
          It does NOT consume the newline.
*/

extern "C" unsigned int FIO_EOLN (FIO_File f);

/*
   WasEOLN - tests to see whether a file, f, has just seen a newline.
*/

extern "C" unsigned int FIO_WasEOLN (FIO_File f);

/*
   ReadChar - returns a character read from file f.
              Sensible to check with IsNoError or EOF after calling
              this function.
*/

extern "C" char FIO_ReadChar (FIO_File f);

/*
   UnReadChar - replaces a character, ch, back into file f.
                This character must have been read by ReadChar
                and it does not allow successive calls.  It may
                only be called if the previous read was successful
                or end of file was seen.
                If the state was previously endoffile then it
                is altered to successful.
                Otherwise it is left alone.
*/

extern "C" void FIO_UnReadChar (FIO_File f, char ch);

/*
   WriteLine - writes out a linefeed to file, f.
*/

extern "C" void FIO_WriteLine (FIO_File f);

/*
   WriteString - writes a string to file, f.
*/

extern "C" void FIO_WriteString (FIO_File f, const char *a_, unsigned int _a_high);

/*
   ReadString - reads a string from file, f, into string, a.
                It terminates the string if HIGH is reached or
                if a newline is seen or an error occurs.
*/

extern "C" void FIO_ReadString (FIO_File f, char *a, unsigned int _a_high);

/*
   WriteCardinal - writes a CARDINAL to file, f.
                   It writes the binary image of the cardinal
                   to file, f.
*/

extern "C" void FIO_WriteCardinal (FIO_File f, unsigned int c);

/*
   ReadCardinal - reads a CARDINAL from file, f.
                  It reads a binary image of a CARDINAL
                  from a file, f.
*/

extern "C" unsigned int FIO_ReadCardinal (FIO_File f);

/*
   GetUnixFileDescriptor - returns the UNIX file descriptor of a file.
*/

extern "C" int FIO_GetUnixFileDescriptor (FIO_File f);

/*
   SetPositionFromBeginning - sets the position from the beginning of the file.
*/

extern "C" void FIO_SetPositionFromBeginning (FIO_File f, long int pos);

/*
   SetPositionFromEnd - sets the position from the end of the file.
*/

extern "C" void FIO_SetPositionFromEnd (FIO_File f, long int pos);

/*
   FindPosition - returns the current absolute position in file, f.
*/

extern "C" long int FIO_FindPosition (FIO_File f);

/*
   GetFileName - assigns, a, with the filename associated with, f.
*/

extern "C" void FIO_GetFileName (FIO_File f, char *a, unsigned int _a_high);

/*
   getFileName - returns the address of the filename associated with, f.
*/

extern "C" void * FIO_getFileName (FIO_File f);

/*
   getFileNameLength - returns the number of characters associated with filename, f.
*/

extern "C" unsigned int FIO_getFileNameLength (FIO_File f);

/*
   FlushOutErr - flushes, StdOut, and, StdErr.
                 It is also called when the application calls M2RTS.Terminate.
                 (which is automatically placed in program modules by the GM2
                 scaffold).
*/

extern "C" void FIO_FlushOutErr (void);

/*
   Max - returns the maximum of two values.
*/

static unsigned int Max (unsigned int a, unsigned int b);

/*
   Min - returns the minimum of two values.
*/

static unsigned int Min (unsigned int a, unsigned int b);

/*
   GetNextFreeDescriptor - returns the index to the FileInfo array indicating
                           the next free slot.
*/

static FIO_File GetNextFreeDescriptor (void);

/*
   SetState - sets the field, state, of file, f, to, s.
*/

static void SetState (FIO_File f, FIO_FileStatus s);

/*
   InitializeFile - initialize a file descriptor
*/

static FIO_File InitializeFile (FIO_File f, void * fname, unsigned int flength, FIO_FileStatus fstate, FIO_FileUsage use, unsigned int towrite, unsigned int buflength);

/*
   ConnectToUnix - connects a FIO file to a UNIX file descriptor.
*/

static void ConnectToUnix (FIO_File f, unsigned int towrite, unsigned int newfile);

/*
   ReadFromBuffer - attempts to read, nBytes, from file, f.
                    It firstly consumes the buffer and then performs
                    direct unbuffered reads. This should only be used
                    when wishing to read large files.

                    The actual number of bytes read is returned.
                    -1 is returned if EOF is reached.
*/

static int ReadFromBuffer (FIO_File f, void * a, unsigned int nBytes);

/*
   BufferedRead - will read, nBytes, through the buffer.
                  Similar to ReadFromBuffer, but this function will always
                  read into the buffer before copying into memory.

                  Useful when performing small reads.
*/

static int BufferedRead (FIO_File f, unsigned int nBytes, void * a);

/*
   HandleEscape - translates 
 and \t into their respective ascii codes.
*/

static void HandleEscape (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, unsigned int *i, unsigned int *j, unsigned int HighSrc, unsigned int HighDest);

/*
   Cast - casts a := b
*/

static void Cast (unsigned char *a, unsigned int _a_high, const unsigned char *b_, unsigned int _b_high);

/*
   StringFormat1 - converts string, src, into, dest, together with encapsulated
                   entity, w. It only formats the first %s or %d with n.
*/

static void StringFormat1 (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, const unsigned char *w_, unsigned int _w_high);

/*
   FormatError - provides a orthoganal counterpart to the procedure below.
*/

static void FormatError (const char *a_, unsigned int _a_high);

/*
   FormatError1 - generic error procedure taking standard format string
                  and single parameter.
*/

static void FormatError1 (const char *a_, unsigned int _a_high, const unsigned char *w_, unsigned int _w_high);

/*
   FormatError2 - generic error procedure taking standard format string
                  and two parameters.
*/

static void FormatError2 (const char *a_, unsigned int _a_high, const unsigned char *w1_, unsigned int _w1_high, const unsigned char *w2_, unsigned int _w2_high);

/*
   CheckAccess - checks to see whether a file f has been
                 opened for read/write.
*/

static void CheckAccess (FIO_File f, FIO_FileUsage use, unsigned int towrite);

/*
   SetEndOfLine -
*/

static void SetEndOfLine (FIO_File f, char ch);

/*
   BufferedWrite - will write, nBytes, through the buffer.
                   Similar to WriteNBytes, but this function will always
                   write into the buffer before copying into memory.

                   Useful when performing small writes.
*/

static int BufferedWrite (FIO_File f, unsigned int nBytes, void * a);

/*
   PreInitialize - preinitialize the file descriptor.
*/

static void PreInitialize (FIO_File f, const char *fname_, unsigned int _fname_high, FIO_FileStatus state, FIO_FileUsage use, unsigned int towrite, int osfd, unsigned int bufsize);

/*
   Init - initialize the modules, global variables.
*/

static void Init (void);


/*
   Max - returns the maximum of two values.
*/

static unsigned int Max (unsigned int a, unsigned int b)
{
  if (a > b)
    {
      return a;
    }
  else
    {
      return b;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   Min - returns the minimum of two values.
*/

static unsigned int Min (unsigned int a, unsigned int b)
{
  if (a < b)
    {
      return a;
    }
  else
    {
      return b;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   GetNextFreeDescriptor - returns the index to the FileInfo array indicating
                           the next free slot.
*/

static FIO_File GetNextFreeDescriptor (void)
{
  FIO_File f;
  FIO_File h;
  FIO_FileDescriptor fd;

  f = Error+1;
  h = Indexing_HighIndice (FileInfo);
  for (;;)
  {
    if (f <= h)
      {
        fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
        if (fd == NULL)
          {
            return f;
          }
      }
    f += 1;
    if (f > h)
      {
        Indexing_PutIndice (FileInfo, f, NULL);  /* create new slot  */
        return f;  /* create new slot  */
      }
  }
  ReturnException ("../../gcc-read-write/gcc/m2/gm2-libs/FIO.def", 25, 1);
  __builtin_unreachable ();
}


/*
   SetState - sets the field, state, of file, f, to, s.
*/

static void SetState (FIO_File f, FIO_FileStatus s)
{
  FIO_FileDescriptor fd;

  fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
  fd->state = s;
}


/*
   InitializeFile - initialize a file descriptor
*/

static FIO_File InitializeFile (FIO_File f, void * fname, unsigned int flength, FIO_FileStatus fstate, FIO_FileUsage use, unsigned int towrite, unsigned int buflength)
{
  FIO_PtrToChar p;
  FIO_FileDescriptor fd;

  Storage_ALLOCATE ((void **) &fd, sizeof (FIO_fds));
  if (fd == NULL)
    {
      SetState (Error, FIO_outofmemory);
      return Error;
    }
  else
    {
      Indexing_PutIndice (FileInfo, f, reinterpret_cast<void *> (fd));
      fd->name.size = flength+1;  /* need to guarantee the nul for C  */
      fd->usage = use;  /* need to guarantee the nul for C  */
      fd->output = towrite;
      Storage_ALLOCATE (&fd->name.address, fd->name.size);
      if (fd->name.address == NULL)
        {
          fd->state = FIO_outofmemory;
          return f;
        }
      fd->name.address = libc_strncpy (fd->name.address, fname, flength);
      /* and assign nul to the last byte  */
      p = static_cast<FIO_PtrToChar> (fd->name.address);
      p += flength;
      (*p) = ASCII_nul;
      fd->abspos = 0;
      /* now for the buffer  */
      Storage_ALLOCATE ((void **) &fd->buffer, sizeof (FIO_buf));
      if (fd->buffer == NULL)
        {
          SetState (Error, FIO_outofmemory);
          return Error;
        }
      else
        {
          fd->buffer->valid = FALSE;
          fd->buffer->bufstart = 0;
          fd->buffer->size = buflength;
          fd->buffer->position = 0;
          fd->buffer->filled = 0;
          if (fd->buffer->size == 0)
            {
              fd->buffer->address = NULL;
            }
          else
            {
              Storage_ALLOCATE (&fd->buffer->address, fd->buffer->size);
              if (fd->buffer->address == NULL)
                {
                  fd->state = FIO_outofmemory;
                  return f;
                }
            }
          if (towrite)
            {
              fd->buffer->left = fd->buffer->size;
            }
          else
            {
              fd->buffer->left = 0;
            }
          fd->buffer->contents = reinterpret_cast<FIO__T7 *> (fd->buffer->address);  /* provides easy access for reading characters  */
          fd->state = fstate;  /* provides easy access for reading characters  */
        }
    }
  return f;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ConnectToUnix - connects a FIO file to a UNIX file descriptor.
*/

static void ConnectToUnix (FIO_File f, unsigned int towrite, unsigned int newfile)
{
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          if (towrite)
            {
              if (newfile)
                {
                  fd->unixfd = libc_creat (fd->name.address, CreatePermissions);
                }
              else
                {
                  fd->unixfd = libc_open (fd->name.address, UNIXWRITEONLY, 0);
                }
            }
          else
            {
              fd->unixfd = libc_open (fd->name.address, UNIXREADONLY, 0);
            }
          if (fd->unixfd < 0)
            {
              fd->state = FIO_connectionfailure;
            }
        }
    }
}


/*
   ReadFromBuffer - attempts to read, nBytes, from file, f.
                    It firstly consumes the buffer and then performs
                    direct unbuffered reads. This should only be used
                    when wishing to read large files.

                    The actual number of bytes read is returned.
                    -1 is returned if EOF is reached.
*/

static int ReadFromBuffer (FIO_File f, void * a, unsigned int nBytes)
{
  typedef unsigned char *ReadFromBuffer__T1;

  void * t;
  int result;
  unsigned int total;
  unsigned int n;
  ReadFromBuffer__T1 p;
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      total = 0;  /* how many bytes have we read  */
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));  /* how many bytes have we read  */
      /* extract from the buffer first  */
      if ((fd->buffer != NULL) && fd->buffer->valid)
        {
          if (fd->buffer->left > 0)
            {
              /* avoid gcc warning by using compound statement even if not strictly necessary.  */
              if (nBytes == 1)
                {
                  /* too expensive to call memcpy for 1 character  */
                  p = static_cast<ReadFromBuffer__T1> (a);
                  (*p) = static_cast<unsigned char> ((*fd->buffer->contents).array[fd->buffer->position]);
                  fd->buffer->left -= 1;  /* remove consumed bytes  */
                  fd->buffer->position += 1;  /* move onwards n bytes  */
                  nBytes = 0;
                  /* read  */
                  return 1;
                }
              else
                {
                  n = Min (fd->buffer->left, nBytes);
                  t = fd->buffer->address;
                  t = reinterpret_cast<void *> (reinterpret_cast<char *> (t)+fd->buffer->position);
                  p = static_cast<ReadFromBuffer__T1> (libc_memcpy (a, t, static_cast<size_t> (n)));
                  fd->buffer->left -= n;  /* remove consumed bytes  */
                  fd->buffer->position += n;  /* move onwards n bytes  */
                  /* move onwards ready for direct reads  */
                  a = reinterpret_cast<void *> (reinterpret_cast<char *> (a)+n);
                  nBytes -= n;  /* reduce the amount for future direct  */
                  /* read  */
                  total += n;
                  return total;  /* much cleaner to return now,  */
                }
               /* difficult to record an error if  */
            }
           /* the read below returns -1  */
        }
      if (nBytes > 0)
        {
          /* still more to read  */
          result = static_cast<int> (libc_read (fd->unixfd, a, static_cast<size_t> ((int ) (nBytes))));
          if (result > 0)
            {
              /* avoid dangling else.  */
              total += result;
              fd->abspos += result;
              /* now disable the buffer as we read directly into, a.  */
              if (fd->buffer != NULL)
                {
                  fd->buffer->valid = FALSE;
                }
            }
          else
            {
              if (result == 0)
                {
                  /* eof reached  */
                  fd->state = FIO_endoffile;
                }
              else
                {
                  fd->state = FIO_failed;
                }
              /* indicate buffer is empty  */
              if (fd->buffer != NULL)
                {
                  fd->buffer->valid = FALSE;
                  fd->buffer->left = 0;
                  fd->buffer->position = 0;
                  if (fd->buffer->address != NULL)
                    {
                      (*fd->buffer->contents).array[fd->buffer->position] = ASCII_nul;
                    }
                }
              return -1;
            }
        }
      return total;
    }
  else
    {
      return -1;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   BufferedRead - will read, nBytes, through the buffer.
                  Similar to ReadFromBuffer, but this function will always
                  read into the buffer before copying into memory.

                  Useful when performing small reads.
*/

static int BufferedRead (FIO_File f, unsigned int nBytes, void * a)
{
  typedef unsigned char *BufferedRead__T3;

  void * t;
  int result;
  int total;
  int n;
  BufferedRead__T3 p;
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      total = 0;  /* how many bytes have we read  */
      if (fd != NULL)  /* how many bytes have we read  */
        {
          /* extract from the buffer first  */
          if (fd->buffer != NULL)
            {
              while (nBytes > 0)
                {
                  if ((fd->buffer->left > 0) && fd->buffer->valid)
                    {
                      if (nBytes == 1)
                        {
                          /* too expensive to call memcpy for 1 character  */
                          p = static_cast<BufferedRead__T3> (a);
                          (*p) = static_cast<unsigned char> ((*fd->buffer->contents).array[fd->buffer->position]);
                          fd->buffer->left -= 1;  /* remove consumed byte  */
                          fd->buffer->position += 1;  /* move onwards n byte  */
                          total += 1;  /* move onwards n byte  */
                          return total;
                        }
                      else
                        {
                          n = Min (fd->buffer->left, nBytes);
                          t = fd->buffer->address;
                          t = reinterpret_cast<void *> (reinterpret_cast<char *> (t)+fd->buffer->position);
                          p = static_cast<BufferedRead__T3> (libc_memcpy (a, t, static_cast<size_t> (n)));
                          fd->buffer->left -= n;  /* remove consumed bytes  */
                          fd->buffer->position += n;  /* move onwards n bytes  */
                          /* move onwards ready for direct reads  */
                          a = reinterpret_cast<void *> (reinterpret_cast<char *> (a)+n);
                          nBytes -= n;  /* reduce the amount for future direct  */
                          /* read  */
                          total += n;
                        }
                    }
                  else
                    {
                      /* refill buffer  */
                      n = static_cast<int> (libc_read (fd->unixfd, fd->buffer->address, static_cast<size_t> (fd->buffer->size)));
                      if (n >= 0)
                        {
                          /* avoid dangling else.  */
                          fd->buffer->valid = TRUE;
                          fd->buffer->position = 0;
                          fd->buffer->left = n;
                          fd->buffer->filled = n;
                          fd->buffer->bufstart = fd->abspos;
                          fd->abspos += n;
                          if (n == 0)
                            {
                              /* eof reached  */
                              fd->state = FIO_endoffile;
                              return -1;
                            }
                        }
                      else
                        {
                          fd->buffer->valid = FALSE;
                          fd->buffer->position = 0;
                          fd->buffer->left = 0;
                          fd->buffer->filled = 0;
                          fd->state = FIO_failed;
                          return total;
                        }
                    }
                }
              return total;
            }
        }
    }
  return -1;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   HandleEscape - translates 
 and \t into their respective ascii codes.
*/

static void HandleEscape (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, unsigned int *i, unsigned int *j, unsigned int HighSrc, unsigned int HighDest)
{
  char src[_src_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (src, src_, _src_high+1);

  if (((((*i)+1) < HighSrc) && (src[(*i)] == '\\')) && ((*j) < HighDest))
    {
      /* avoid gcc warning by using compound statement even if not strictly necessary.  */
      if (src[(*i)+1] == 'n')
        {
          /* requires a newline  */
          dest[(*j)] = ASCII_nl;
          (*j) += 1;
          (*i) += 2;
        }
      else if (src[(*i)+1] == 't')
        {
          /* avoid dangling else.  */
          /* requires a tab (yuck) tempted to fake this but I better not..  */
          dest[(*j)] = ASCII_tab;
          (*j) += 1;
          (*i) += 2;
        }
      else
        {
          /* avoid dangling else.  */
          /* copy escaped character  */
          (*i) += 1;
          dest[(*j)] = src[(*i)];
          (*j) += 1;
          (*i) += 1;
        }
    }
}


/*
   Cast - casts a := b
*/

static void Cast (unsigned char *a, unsigned int _a_high, const unsigned char *b_, unsigned int _b_high)
{
  unsigned int i;
  unsigned char b[_b_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (b, b_, _b_high+1);

  if (_a_high == _b_high)
    {
      for (i=0; i<=_a_high; i++)
        {
          a[i] = b[i];
        }
    }
  else
    {
      FormatError ((const char *) "cast failed", 11);
    }
}


/*
   StringFormat1 - converts string, src, into, dest, together with encapsulated
                   entity, w. It only formats the first %s or %d with n.
*/

static void StringFormat1 (char *dest, unsigned int _dest_high, const char *src_, unsigned int _src_high, const unsigned char *w_, unsigned int _w_high)
{
  typedef struct StringFormat1__T8_a StringFormat1__T8;

  typedef char *StringFormat1__T4;

  struct StringFormat1__T8_a { char array[MaxErrorString+1]; };
  unsigned int HighSrc;
  unsigned int HighDest;
  unsigned int c;
  unsigned int i;
  unsigned int j;
  StringFormat1__T8 str;
  StringFormat1__T4 p;
  char src[_src_high+1];
  unsigned char w[_w_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (src, src_, _src_high+1);
  memcpy (w, w_, _w_high+1);

  HighSrc = StrLib_StrLen ((const char *) src, _src_high);
  HighDest = _dest_high;
  p = NULL;
  c = 0;
  i = 0;
  j = 0;
  while ((((i < HighSrc) && (src[i] != ASCII_nul)) && (j < HighDest)) && (src[i] != '%'))
    {
      if (src[i] == '\\')
        {
          HandleEscape ((char *) dest, _dest_high, (const char *) src, _src_high, &i, &j, HighSrc, HighDest);
        }
      else
        {
          dest[j] = src[i];
          i += 1;
          j += 1;
        }
    }
  if ((((i+1) < HighSrc) && (src[i] == '%')) && (j < HighDest))
    {
      /* avoid gcc warning by using compound statement even if not strictly necessary.  */
      if (src[i+1] == 's')
        {
          Cast ((unsigned char *) &p, (sizeof (p)-1), (const unsigned char *) w, _w_high);
          while ((j < HighDest) && ((*p) != ASCII_nul))
            {
              dest[j] = (*p);
              j += 1;
              p += 1;
            }
          if (j < HighDest)
            {
              dest[j] = ASCII_nul;
            }
          j = StrLib_StrLen ((const char *) dest, _dest_high);
          i += 2;
        }
      else if (src[i+1] == 'd')
        {
          /* avoid dangling else.  */
          dest[j] = ASCII_nul;
          Cast ((unsigned char *) &c, (sizeof (c)-1), (const unsigned char *) w, _w_high);
          NumberIO_CardToStr (c, 0, (char *) &str.array[0], MaxErrorString);
          StrLib_StrConCat ((const char *) dest, _dest_high, (const char *) &str.array[0], MaxErrorString, (char *) dest, _dest_high);
          j = StrLib_StrLen ((const char *) dest, _dest_high);
          i += 2;
        }
      else
        {
          /* avoid dangling else.  */
          dest[j] = src[i];
          i += 1;
          j += 1;
        }
    }
  /* and finish off copying src into dest  */
  while (((i < HighSrc) && (src[i] != ASCII_nul)) && (j < HighDest))
    {
      if (src[i] == '\\')
        {
          HandleEscape ((char *) dest, _dest_high, (const char *) src, _src_high, &i, &j, HighSrc, HighDest);
        }
      else
        {
          dest[j] = src[i];
          i += 1;
          j += 1;
        }
    }
  if (j < HighDest)
    {
      dest[j] = ASCII_nul;
    }
}


/*
   FormatError - provides a orthoganal counterpart to the procedure below.
*/

static void FormatError (const char *a_, unsigned int _a_high)
{
  char a[_a_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);

  FIO_WriteString (FIO_StdErr, (const char *) a, _a_high);
}


/*
   FormatError1 - generic error procedure taking standard format string
                  and single parameter.
*/

static void FormatError1 (const char *a_, unsigned int _a_high, const unsigned char *w_, unsigned int _w_high)
{
  typedef struct FormatError1__T9_a FormatError1__T9;

  struct FormatError1__T9_a { char array[MaxErrorString+1]; };
  FormatError1__T9 s;
  char a[_a_high+1];
  unsigned char w[_w_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);
  memcpy (w, w_, _w_high+1);

  StringFormat1 ((char *) &s.array[0], MaxErrorString, (const char *) a, _a_high, (const unsigned char *) w, _w_high);
  FormatError ((const char *) &s.array[0], MaxErrorString);
}


/*
   FormatError2 - generic error procedure taking standard format string
                  and two parameters.
*/

static void FormatError2 (const char *a_, unsigned int _a_high, const unsigned char *w1_, unsigned int _w1_high, const unsigned char *w2_, unsigned int _w2_high)
{
  typedef struct FormatError2__T10_a FormatError2__T10;

  struct FormatError2__T10_a { char array[MaxErrorString+1]; };
  FormatError2__T10 s;
  char a[_a_high+1];
  unsigned char w1[_w1_high+1];
  unsigned char w2[_w2_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);
  memcpy (w1, w1_, _w1_high+1);
  memcpy (w2, w2_, _w2_high+1);

  StringFormat1 ((char *) &s.array[0], MaxErrorString, (const char *) a, _a_high, (const unsigned char *) w1, _w1_high);
  FormatError1 ((const char *) &s.array[0], MaxErrorString, (const unsigned char *) w2, _w2_high);
}


/*
   CheckAccess - checks to see whether a file f has been
                 opened for read/write.
*/

static void CheckAccess (FIO_File f, FIO_FileUsage use, unsigned int towrite)
{
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      /* avoid dangling else.  */
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd == NULL)
        {
          if (f != FIO_StdErr)
            {
              FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96);
            }
          M2RTS_HALT (-1);
          __builtin_unreachable ();
        }
      else
        {
          if ((use == FIO_openedforwrite) && (fd->usage == FIO_openedforread))
            {
              FormatError1 ((const char *) "this file (%s) has been opened for reading but is now being written\\n", 69, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1));
              M2RTS_HALT (-1);
              __builtin_unreachable ();
            }
          else if ((use == FIO_openedforread) && (fd->usage == FIO_openedforwrite))
            {
              /* avoid dangling else.  */
              FormatError1 ((const char *) "this file (%s) has been opened for writing but is now being read\\n", 66, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1));
              M2RTS_HALT (-1);
              __builtin_unreachable ();
            }
          else if (fd->state == FIO_connectionfailure)
            {
              /* avoid dangling else.  */
              FormatError1 ((const char *) "this file (%s) was not successfully opened\\n", 44, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1));
              M2RTS_HALT (-1);
              __builtin_unreachable ();
            }
          else if (towrite != fd->output)
            {
              /* avoid dangling else.  */
              if (fd->output)
                {
                  FormatError1 ((const char *) "this file (%s) was opened for writing but is now being read\\n", 61, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1));
                  M2RTS_HALT (-1);
                  __builtin_unreachable ();
                }
              else
                {
                  FormatError1 ((const char *) "this file (%s) was opened for reading but is now being written\\n", 64, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1));
                  M2RTS_HALT (-1);
                  __builtin_unreachable ();
                }
            }
        }
    }
  else
    {
      FormatError ((const char *) "this file has not been opened successfully\\n", 44);
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
}


/*
   SetEndOfLine -
*/

static void SetEndOfLine (FIO_File f, char ch)
{
  FIO_FileDescriptor fd;

  CheckAccess (f, FIO_openedforread, FALSE);
  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (ch == ASCII_nl)
        {
          fd->state = FIO_endofline;
        }
      else
        {
          fd->state = FIO_successful;
        }
    }
}


/*
   BufferedWrite - will write, nBytes, through the buffer.
                   Similar to WriteNBytes, but this function will always
                   write into the buffer before copying into memory.

                   Useful when performing small writes.
*/

static int BufferedWrite (FIO_File f, unsigned int nBytes, void * a)
{
  typedef unsigned char *BufferedWrite__T5;

  void * t;
  int result;
  int total;
  int n;
  BufferedWrite__T5 p;
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          total = 0;  /* how many bytes have we read  */
          if (fd->buffer != NULL)  /* how many bytes have we read  */
            {
              /* place into the buffer first  */
              while (nBytes > 0)
                {
                  if (fd->buffer->left > 0)
                    {
                      if (nBytes == 1)
                        {
                          /* too expensive to call memcpy for 1 character  */
                          p = static_cast<BufferedWrite__T5> (a);
                          (*fd->buffer->contents).array[fd->buffer->position] = static_cast<char> ((*p));
                          fd->buffer->left -= 1;  /* reduce space  */
                          fd->buffer->position += 1;  /* move onwards n byte  */
                          total += 1;  /* move onwards n byte  */
                          return total;
                        }
                      else
                        {
                          n = Min (fd->buffer->left, nBytes);
                          t = fd->buffer->address;
                          t = reinterpret_cast<void *> (reinterpret_cast<char *> (t)+fd->buffer->position);
                          p = static_cast<BufferedWrite__T5> (libc_memcpy (a, t, static_cast<size_t> ((unsigned int ) (n))));
                          fd->buffer->left -= n;  /* remove consumed bytes  */
                          fd->buffer->position += n;  /* move onwards n bytes  */
                          /* move ready for further writes  */
                          a = reinterpret_cast<void *> (reinterpret_cast<char *> (a)+n);
                          nBytes -= n;  /* reduce the amount for future writes  */
                          total += n;  /* reduce the amount for future writes  */
                        }
                    }
                  else
                    {
                      FIO_FlushBuffer (f);
                      if ((fd->state != FIO_successful) && (fd->state != FIO_endofline))
                        {
                          nBytes = 0;
                        }
                    }
                }
              return total;
            }
        }
    }
  return -1;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   PreInitialize - preinitialize the file descriptor.
*/

static void PreInitialize (FIO_File f, const char *fname_, unsigned int _fname_high, FIO_FileStatus state, FIO_FileUsage use, unsigned int towrite, int osfd, unsigned int bufsize)
{
  FIO_FileDescriptor fd;
  FIO_FileDescriptor fe;
  char fname[_fname_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (fname, fname_, _fname_high+1);

  if ((InitializeFile (f, &fname, StrLib_StrLen ((const char *) fname, _fname_high), state, use, towrite, bufsize)) == f)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (f == Error)
        {
          fe = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, FIO_StdErr));
          if (fe == NULL)
            {
              M2RTS_HALT (-1);
              __builtin_unreachable ();
            }
          else
            {
              fd->unixfd = fe->unixfd;  /* the error channel  */
            }
        }
      else
        {
          fd->unixfd = osfd;
        }
    }
  else
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
}


/*
   Init - initialize the modules, global variables.
*/

static void Init (void)
{
  FileInfo = Indexing_InitIndex (0);
  Error = 0;
  PreInitialize (Error, (const char *) "error", 5, FIO_toomanyfilesopen, FIO_unused, FALSE, -1, 0);
  FIO_StdIn = 1;
  PreInitialize (FIO_StdIn, (const char *) "<stdin>", 7, FIO_successful, FIO_openedforread, FALSE, 0, MaxBufferLength);
  FIO_StdOut = 2;
  PreInitialize (FIO_StdOut, (const char *) "<stdout>", 8, FIO_successful, FIO_openedforwrite, TRUE, 1, MaxBufferLength);
  FIO_StdErr = 3;
  PreInitialize (FIO_StdErr, (const char *) "<stderr>", 8, FIO_successful, FIO_openedforwrite, TRUE, 2, MaxBufferLength);
  if (! (M2RTS_InstallTerminationProcedure ((PROC ) {(PROC_t) FIO_FlushOutErr})))
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
}


/*
   IsNoError - returns a TRUE if no error has occured on file, f.
*/

extern "C" unsigned int FIO_IsNoError (FIO_File f)
{
  FIO_FileDescriptor fd;

  if (f == Error)
    {
      return FALSE;
    }
  else
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      return (fd != NULL) && (((fd->state == FIO_successful) || (fd->state == FIO_endoffile)) || (fd->state == FIO_endofline));
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   IsActive - returns TRUE if the file, f, is still active.
*/

extern "C" unsigned int FIO_IsActive (FIO_File f)
{
  if (f == Error)
    {
      return FALSE;
    }
  else
    {
      return (Indexing_GetIndice (FileInfo, f)) != NULL;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" unsigned int FIO_Exists (const char *fname_, unsigned int _fname_high)
{
  char fname[_fname_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (fname, fname_, _fname_high+1);

  /* 
   The following functions are wrappers for the above.
  */
  return FIO_exists (&fname, StrLib_StrLen ((const char *) fname, _fname_high));
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" FIO_File FIO_OpenToRead (const char *fname_, unsigned int _fname_high)
{
  char fname[_fname_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (fname, fname_, _fname_high+1);

  return FIO_openToRead (&fname, StrLib_StrLen ((const char *) fname, _fname_high));
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" FIO_File FIO_OpenToWrite (const char *fname_, unsigned int _fname_high)
{
  char fname[_fname_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (fname, fname_, _fname_high+1);

  return FIO_openToWrite (&fname, StrLib_StrLen ((const char *) fname, _fname_high));
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" FIO_File FIO_OpenForRandom (const char *fname_, unsigned int _fname_high, unsigned int towrite, unsigned int newfile)
{
  char fname[_fname_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (fname, fname_, _fname_high+1);

  return FIO_openForRandom (&fname, StrLib_StrLen ((const char *) fname, _fname_high), towrite, newfile);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   Close - close a file which has been previously opened using:
           OpenToRead, OpenToWrite, OpenForRandom.
           It is correct to close a file which has an error status.
*/

extern "C" void FIO_Close (FIO_File f)
{
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      /* 
         we allow users to close files which have an error status
  */
      if (fd != NULL)
        {
          FIO_FlushBuffer (f);
          if (fd->unixfd >= 0)
            {
              if ((libc_close (fd->unixfd)) != 0)
                {
                  FormatError1 ((const char *) "failed to close file (%s)\\n", 27, (const unsigned char *) &fd->name.address, (sizeof (fd->name.address)-1));
                  fd->state = FIO_failed;  /* --fixme-- too late to notify user (unless we return a BOOLEAN)  */
                }
            }
          if (fd->name.address != NULL)
            {
              Storage_DEALLOCATE (&fd->name.address, fd->name.size);
            }
          if (fd->buffer != NULL)
            {
              if (fd->buffer->address != NULL)
                {
                  Storage_DEALLOCATE (&fd->buffer->address, fd->buffer->size);
                }
              Storage_DEALLOCATE ((void **) &fd->buffer, sizeof (FIO_buf));
              fd->buffer = NULL;
            }
          Storage_DEALLOCATE ((void **) &fd, sizeof (FIO_fds));
          Indexing_PutIndice (FileInfo, f, NULL);
        }
    }
}


/*
   exists - returns TRUE if a file named, fname exists for reading.
*/

extern "C" unsigned int FIO_exists (void * fname, unsigned int flength)
{
  FIO_File f;

  f = FIO_openToRead (fname, flength);
  if (FIO_IsNoError (f))
    {
      FIO_Close (f);
      return TRUE;
    }
  else
    {
      FIO_Close (f);
      return FALSE;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   openToRead - attempts to open a file, fname, for reading and
                it returns this file.
                The success of this operation can be checked by
                calling IsNoError.
*/

extern "C" FIO_File FIO_openToRead (void * fname, unsigned int flength)
{
  FIO_File f;

  f = GetNextFreeDescriptor ();
  if (f == Error)
    {
      SetState (f, FIO_toomanyfilesopen);
    }
  else
    {
      f = InitializeFile (f, fname, flength, FIO_successful, FIO_openedforread, FALSE, MaxBufferLength);
      ConnectToUnix (f, FALSE, FALSE);
    }
  return f;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   openToWrite - attempts to open a file, fname, for write and
                 it returns this file.
                 The success of this operation can be checked by
                 calling IsNoError.
*/

extern "C" FIO_File FIO_openToWrite (void * fname, unsigned int flength)
{
  FIO_File f;

  f = GetNextFreeDescriptor ();
  if (f == Error)
    {
      SetState (f, FIO_toomanyfilesopen);
    }
  else
    {
      f = InitializeFile (f, fname, flength, FIO_successful, FIO_openedforwrite, TRUE, MaxBufferLength);
      ConnectToUnix (f, TRUE, TRUE);
    }
  return f;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   openForRandom - attempts to open a file, fname, for random access
                   read or write and it returns this file.
                   The success of this operation can be checked by
                   calling IsNoError.
                   towrite, determines whether the file should be
                   opened for writing or reading.
*/

extern "C" FIO_File FIO_openForRandom (void * fname, unsigned int flength, unsigned int towrite, unsigned int newfile)
{
  FIO_File f;

  f = GetNextFreeDescriptor ();
  if (f == Error)
    {
      SetState (f, FIO_toomanyfilesopen);
    }
  else
    {
      f = InitializeFile (f, fname, flength, FIO_successful, FIO_openedforrandom, towrite, MaxBufferLength);
      ConnectToUnix (f, towrite, newfile);
    }
  return f;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FlushBuffer - flush contents of file, f.
*/

extern "C" void FIO_FlushBuffer (FIO_File f)
{
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          if (fd->output && (fd->buffer != NULL))
            {
              if ((fd->buffer->position == 0) || ((libc_write (fd->unixfd, fd->buffer->address, static_cast<size_t> (fd->buffer->position))) == ((int ) (fd->buffer->position))))
                {
                  fd->abspos += fd->buffer->position;
                  fd->buffer->bufstart = fd->abspos;
                  fd->buffer->position = 0;
                  fd->buffer->filled = 0;
                  fd->buffer->left = fd->buffer->size;
                }
              else
                {
                  fd->state = FIO_failed;
                }
            }
        }
    }
}


/*
   ReadNBytes - reads nBytes of a file into memory area, dest, returning
                the number of bytes actually read.
                This function will consume from the buffer and then
                perform direct libc reads. It is ideal for large reads.
*/

extern "C" unsigned int FIO_ReadNBytes (FIO_File f, unsigned int nBytes, void * dest)
{
  typedef char *ReadNBytes__T2;

  int n;
  ReadNBytes__T2 p;

  if (f != Error)
    {
      CheckAccess (f, FIO_openedforread, FALSE);
      n = ReadFromBuffer (f, dest, nBytes);
      if (n <= 0)
        {
          return 0;
        }
      else
        {
          p = static_cast<ReadNBytes__T2> (dest);
          p += n-1;
          SetEndOfLine (f, (*p));
          return n;
        }
    }
  else
    {
      return 0;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ReadAny - reads HIGH(a) bytes into, a. All input
             is fully buffered, unlike ReadNBytes and thus is more
             suited to small reads.
*/

extern "C" void FIO_ReadAny (FIO_File f, unsigned char *a, unsigned int _a_high)
{
  CheckAccess (f, FIO_openedforread, FALSE);
  if ((BufferedRead (f, _a_high, a)) == ((int ) (_a_high)))
    {
      SetEndOfLine (f, static_cast<char> (a[_a_high]));
    }
}


/*
   WriteNBytes - writes nBytes from memory area src to a file
                 returning the number of bytes actually written.
                 This function will flush the buffer and then
                 write the nBytes using a direct write from libc.
                 It is ideal for large writes.
*/

extern "C" unsigned int FIO_WriteNBytes (FIO_File f, unsigned int nBytes, void * src)
{
  int total;
  FIO_FileDescriptor fd;

  CheckAccess (f, FIO_openedforwrite, TRUE);
  FIO_FlushBuffer (f);
  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          total = static_cast<int> (libc_write (fd->unixfd, src, static_cast<size_t> ((int ) (nBytes))));
          if (total < 0)
            {
              fd->state = FIO_failed;
              return 0;
            }
          else
            {
              fd->abspos += (unsigned int ) (total);
              if (fd->buffer != NULL)
                {
                  fd->buffer->bufstart = fd->abspos;
                }
              return (unsigned int ) (total);
            }
        }
    }
  return 0;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   WriteAny - writes HIGH(a) bytes onto, file, f. All output
              is fully buffered, unlike WriteNBytes and thus is more
              suited to small writes.
*/

extern "C" void FIO_WriteAny (FIO_File f, unsigned char *a, unsigned int _a_high)
{
  CheckAccess (f, FIO_openedforwrite, TRUE);
  if ((BufferedWrite (f, _a_high, a)) == ((int ) (_a_high)))
    {}  /* empty.  */
}


/*
   WriteChar - writes a single character to file, f.
*/

extern "C" void FIO_WriteChar (FIO_File f, char ch)
{
  CheckAccess (f, FIO_openedforwrite, TRUE);
  if ((BufferedWrite (f, sizeof (ch), &ch)) == ((int ) (sizeof (ch))))
    {}  /* empty.  */
}


/*
   EOF - tests to see whether a file, f, has reached end of file.
*/

extern "C" unsigned int FIO_EOF (FIO_File f)
{
  FIO_FileDescriptor fd;

  CheckAccess (f, FIO_openedforread, FALSE);
  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          return fd->state == FIO_endoffile;
        }
    }
  return TRUE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   EOLN - tests to see whether a file, f, is upon a newline.
          It does NOT consume the newline.
*/

extern "C" unsigned int FIO_EOLN (FIO_File f)
{
  char ch;
  FIO_FileDescriptor fd;

  CheckAccess (f, FIO_openedforread, FALSE);
  /* 
      we will read a character and then push it back onto the input stream,
      having noted the file status, we also reset the status.
  */
  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          if ((fd->state == FIO_successful) || (fd->state == FIO_endofline))
            {
              ch = FIO_ReadChar (f);
              if ((fd->state == FIO_successful) || (fd->state == FIO_endofline))
                {
                  FIO_UnReadChar (f, ch);
                }
              return ch == ASCII_nl;
            }
        }
    }
  return FALSE;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   WasEOLN - tests to see whether a file, f, has just seen a newline.
*/

extern "C" unsigned int FIO_WasEOLN (FIO_File f)
{
  FIO_FileDescriptor fd;

  CheckAccess (f, FIO_openedforread, FALSE);
  if (f == Error)
    {
      return FALSE;
    }
  else
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      return (fd != NULL) && (fd->state == FIO_endofline);
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   ReadChar - returns a character read from file f.
              Sensible to check with IsNoError or EOF after calling
              this function.
*/

extern "C" char FIO_ReadChar (FIO_File f)
{
  char ch;

  CheckAccess (f, FIO_openedforread, FALSE);
  if ((BufferedRead (f, sizeof (ch), &ch)) == ((int ) (sizeof (ch))))
    {
      SetEndOfLine (f, ch);
      return ch;
    }
  else
    {
      return ASCII_nul;
    }
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   UnReadChar - replaces a character, ch, back into file f.
                This character must have been read by ReadChar
                and it does not allow successive calls.  It may
                only be called if the previous read was successful
                or end of file was seen.
                If the state was previously endoffile then it
                is altered to successful.
                Otherwise it is left alone.
*/

extern "C" void FIO_UnReadChar (FIO_File f, char ch)
{
  FIO_FileDescriptor fd;
  unsigned int n;
  void * a;
  void * b;

  CheckAccess (f, FIO_openedforread, FALSE);
  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (((fd->state == FIO_successful) || (fd->state == FIO_endoffile)) || (fd->state == FIO_endofline))
        {
          /* avoid dangling else.  */
          if ((fd->buffer != NULL) && fd->buffer->valid)
            {
              /* we assume that a ReadChar has occurred, we will check just in case.  */
              if (fd->state == FIO_endoffile)
                {
                  fd->buffer->position = MaxBufferLength;
                  fd->buffer->left = 0;
                  fd->buffer->filled = 0;
                  fd->state = FIO_successful;
                }
              if (fd->buffer->position > 0)
                {
                  fd->buffer->position -= 1;
                  fd->buffer->left += 1;
                  (*fd->buffer->contents).array[fd->buffer->position] = ch;
                }
              else
                {
                  /* if possible make room and store ch  */
                  if (fd->buffer->filled == fd->buffer->size)
                    {
                      FormatError1 ((const char *) "performing too many UnReadChar calls on file (%d)\\n", 51, (const unsigned char *) &f, (sizeof (f)-1));
                    }
                  else
                    {
                      n = fd->buffer->filled-fd->buffer->position;
                      b = &(*fd->buffer->contents).array[fd->buffer->position];
                      a = &(*fd->buffer->contents).array[fd->buffer->position+1];
                      a = libc_memcpy (a, b, static_cast<size_t> (n));
                      fd->buffer->filled += 1;
                      (*fd->buffer->contents).array[fd->buffer->position] = ch;
                    }
                }
            }
        }
      else
        {
          FormatError1 ((const char *) "UnReadChar can only be called if the previous read was successful or end of file, error on file (%d)\\n", 102, (const unsigned char *) &f, (sizeof (f)-1));
        }
    }
}


/*
   WriteLine - writes out a linefeed to file, f.
*/

extern "C" void FIO_WriteLine (FIO_File f)
{
  FIO_WriteChar (f, ASCII_nl);
}


/*
   WriteString - writes a string to file, f.
*/

extern "C" void FIO_WriteString (FIO_File f, const char *a_, unsigned int _a_high)
{
  unsigned int l;
  char a[_a_high+1];

  /* make a local copy of each unbounded array.  */
  memcpy (a, a_, _a_high+1);

  l = StrLib_StrLen ((const char *) a, _a_high);
  if ((FIO_WriteNBytes (f, l, &a)) != l)
    {}  /* empty.  */
}


/*
   ReadString - reads a string from file, f, into string, a.
                It terminates the string if HIGH is reached or
                if a newline is seen or an error occurs.
*/

extern "C" void FIO_ReadString (FIO_File f, char *a, unsigned int _a_high)
{
  unsigned int high;
  unsigned int i;
  char ch;

  CheckAccess (f, FIO_openedforread, FALSE);
  high = _a_high;
  i = 0;
  do {
    ch = FIO_ReadChar (f);
    if (i <= high)
      {
        /* avoid gcc warning by using compound statement even if not strictly necessary.  */
        if (((ch == ASCII_nl) || (! (FIO_IsNoError (f)))) || (FIO_EOF (f)))
          {
            a[i] = ASCII_nul;
            i += 1;
          }
        else
          {
            a[i] = ch;
            i += 1;
          }
      }
  } while (! ((((ch == ASCII_nl) || (i > high)) || (! (FIO_IsNoError (f)))) || (FIO_EOF (f))));
}


/*
   WriteCardinal - writes a CARDINAL to file, f.
                   It writes the binary image of the cardinal
                   to file, f.
*/

extern "C" void FIO_WriteCardinal (FIO_File f, unsigned int c)
{
  FIO_WriteAny (f, (unsigned char *) &c, (sizeof (c)-1));
}


/*
   ReadCardinal - reads a CARDINAL from file, f.
                  It reads a binary image of a CARDINAL
                  from a file, f.
*/

extern "C" unsigned int FIO_ReadCardinal (FIO_File f)
{
  unsigned int c;

  FIO_ReadAny (f, (unsigned char *) &c, (sizeof (c)-1));
  return c;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   GetUnixFileDescriptor - returns the UNIX file descriptor of a file.
*/

extern "C" int FIO_GetUnixFileDescriptor (FIO_File f)
{
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          return fd->unixfd;
        }
    }
  FormatError1 ((const char *) "file %d has not been opened or is out of range\\n", 48, (const unsigned char *) &f, (sizeof (f)-1));
  return -1;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   SetPositionFromBeginning - sets the position from the beginning of the file.
*/

extern "C" void FIO_SetPositionFromBeginning (FIO_File f, long int pos)
{
  long int offset;
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          /* always force the lseek, until we are confident that abspos is always correct,
               basically it needs some hard testing before we should remove the OR TRUE.  */
          if ((fd->abspos != pos) || TRUE)
            {
              FIO_FlushBuffer (f);
              if (fd->buffer != NULL)
                {
                  if (fd->output)
                    {
                      fd->buffer->left = fd->buffer->size;
                    }
                  else
                    {
                      fd->buffer->left = 0;
                    }
                  fd->buffer->position = 0;
                  fd->buffer->filled = 0;
                }
              offset = libc_lseek (fd->unixfd, pos, SEEK_SET);
              if ((offset >= 0) && (pos == offset))
                {
                  fd->abspos = pos;
                }
              else
                {
                  fd->state = FIO_failed;
                  fd->abspos = 0;
                }
              if (fd->buffer != NULL)
                {
                  fd->buffer->valid = FALSE;
                  fd->buffer->bufstart = fd->abspos;
                }
            }
        }
    }
}


/*
   SetPositionFromEnd - sets the position from the end of the file.
*/

extern "C" void FIO_SetPositionFromEnd (FIO_File f, long int pos)
{
  long int offset;
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          FIO_FlushBuffer (f);
          if (fd->buffer != NULL)
            {
              if (fd->output)
                {
                  fd->buffer->left = fd->buffer->size;
                }
              else
                {
                  fd->buffer->left = 0;
                }
              fd->buffer->position = 0;
              fd->buffer->filled = 0;
            }
          offset = libc_lseek (fd->unixfd, pos, SEEK_END);
          if (offset >= 0)
            {
              fd->abspos = offset;
            }
          else
            {
              fd->state = FIO_failed;
              fd->abspos = 0;
              offset = 0;
            }
          if (fd->buffer != NULL)
            {
              fd->buffer->valid = FALSE;
              fd->buffer->bufstart = offset;
            }
        }
    }
}


/*
   FindPosition - returns the current absolute position in file, f.
*/

extern "C" long int FIO_FindPosition (FIO_File f)
{
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd != NULL)
        {
          if ((fd->buffer == NULL) || ! fd->buffer->valid)
            {
              return fd->abspos;
            }
          else
            {
              return fd->buffer->bufstart+((long int ) (fd->buffer->position));
            }
        }
    }
  return 0;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   GetFileName - assigns, a, with the filename associated with, f.
*/

extern "C" void FIO_GetFileName (FIO_File f, char *a, unsigned int _a_high)
{
  typedef char *GetFileName__T6;

  unsigned int i;
  GetFileName__T6 p;
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd == NULL)
        {
          FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96);
          M2RTS_HALT (-1);
          __builtin_unreachable ();
        }
      else
        {
          if (fd->name.address == NULL)
            {
              StrLib_StrCopy ((const char *) "", 0, (char *) a, _a_high);
            }
          else
            {
              p = static_cast<GetFileName__T6> (fd->name.address);
              i = 0;
              while (((*p) != ASCII_nul) && (i <= _a_high))
                {
                  a[i] = (*p);
                  p += 1;
                  i += 1;
                }
            }
        }
    }
}


/*
   getFileName - returns the address of the filename associated with, f.
*/

extern "C" void * FIO_getFileName (FIO_File f)
{
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd == NULL)
        {
          FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96);
          M2RTS_HALT (-1);
          __builtin_unreachable ();
        }
      else
        {
          return fd->name.address;
        }
    }
  return NULL;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   getFileNameLength - returns the number of characters associated with filename, f.
*/

extern "C" unsigned int FIO_getFileNameLength (FIO_File f)
{
  FIO_FileDescriptor fd;

  if (f != Error)
    {
      fd = static_cast<FIO_FileDescriptor> (Indexing_GetIndice (FileInfo, f));
      if (fd == NULL)
        {
          FormatError ((const char *) "this file has probably been closed and not reopened successfully or alternatively never opened\\n", 96);
          M2RTS_HALT (-1);
          __builtin_unreachable ();
        }
      else
        {
          return fd->name.size;
        }
    }
  return 0;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FlushOutErr - flushes, StdOut, and, StdErr.
                 It is also called when the application calls M2RTS.Terminate.
                 (which is automatically placed in program modules by the GM2
                 scaffold).
*/

extern "C" void FIO_FlushOutErr (void)
{
  if (FIO_IsNoError (FIO_StdOut))
    {
      FIO_FlushBuffer (FIO_StdOut);
    }
  if (FIO_IsNoError (FIO_StdErr))
    {
      FIO_FlushBuffer (FIO_StdErr);
    }
}

extern "C" void _M2_FIO_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
  Init ();
}

extern "C" void _M2_FIO_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
  FIO_FlushOutErr ();
}
